﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Threading;
using Jacobi.Vst.Core;
using Jacobi.Vst.Interop.Host;
using BlueWave.Interop.Asio;

namespace KinectedMusic.Audio
{

    class AudioOut
    {
        private AsioDriver driver;

        // the asio driver we are using
        private const int ASIODRIVER = 0;

        private SongControl songControl;

        // should i store locally????
        public int BufferSize
        {
            get
            {
                return driver.OutputChannels[0].BufferSize;
            }
        }

        public double SampleRate
        {
            get
            {
                return driver.SampleRate;
            }
        }

        //private List<Instrument> instruments;



        public AudioOut(SongControl songControl)
        {
            this.songControl = songControl;
            LoadDriver();
        }

        //public void SetInstruments(List<Instrument> instruments)
        //{
        //    this.instruments = instruments;
        //}

        private void LoadDriver()
        {
            // if no drivers present exit
            if (AsioDriver.InstalledDrivers.Length == 0)
            {
                Console.WriteLine("No ASIO drivers installed.");
                Console.ReadLine();
                return;
            }

            // show all drivers on the system
            Console.WriteLine("Displaying ASIO drivers on the system:");
            for (int index = 0; index < AsioDriver.InstalledDrivers.Length; index++)
            {
                Console.WriteLine(AsioDriver.InstalledDrivers[index]);
            }

            // load the asio driver
           driver = AsioDriver.SelectDriver(AsioDriver.InstalledDrivers[ASIODRIVER]);


            Console.WriteLine("  Driver name = " + driver.DriverName);
            Console.WriteLine("  Driver version = " + driver.Version);
            Console.WriteLine("  Input channels = " + driver.NumberInputChannels);
            Console.WriteLine("  Output channels = " + driver.NumberOutputChannels);
            Console.WriteLine("  Min buffer size = " + driver.BufferSizex.MinSize);
            Console.WriteLine("  Max buffer size = " + driver.BufferSizex.MaxSize);
            Console.WriteLine("  Preferred buffer size = " + driver.BufferSizex.PreferredSize);
            Console.WriteLine("  Granularity = " + driver.BufferSizex.Granularity);
            Console.WriteLine("  Sample rate = " + driver.SampleRate);


            // get our driver wrapper to create its buffers
            driver.CreateBuffers(true);

            // this is our buffer fill event we need to respond to
            driver.BufferUpdate += new EventHandler(AsioDriverBufferUpdate);
        }

        public void StartDriver()
        {
            driver.Start();
        }

        public void StopDriver()
        {
            driver.Stop();
        }


        public void AsioDriverBufferUpdate(object sender, EventArgs e)
        {
            // the driver is the sender
            AsioDriver driver = sender as AsioDriver;
            
            // get the input channel and the stereo output channels
            Channel input = driver.InputChannels[0];
            Channel leftOutput = driver.OutputChannels[0];
            Channel rightOutput = driver.OutputChannels[1];

            List<VstAudioBuffer[]> outputBuffers = songControl.GetOutputBuffers();

            for (int i = 0; i < outputBuffers.Count; i++)
            {
                VstAudioBuffer[]  outputBuffer = outputBuffers[i];
                for (int j = 0; j < BufferSize; j++)
                {
                    if (i != 0)
                    {
                        leftOutput[j] += outputBuffer[0][j];
                        rightOutput[j] += outputBuffer[1][j];
                    }
                    else
                    {
                        leftOutput[j] = outputBuffer[0][j];
                        rightOutput[j] = outputBuffer[1][j];
                    }
                }
            }
        }

    }
}
